package com.zm.blog.handle;

import com.alibaba.fastjson.JSON;
import com.zm.blog.config.BlogResult;
import com.zm.blog.enums.CodeMsg;
import com.zm.blog.utils.BlogUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author: Sister Xiao Ming
 * @Description: 全局异常处理器，它捕获所有异常并返回一个统一的响应格式
 */
@Slf4j
@ControllerAdvice
public class BlogExceptionHandler {

    // 日志消息常量
    private static final String REQUEST_URL_MSG = "请求URL: {}";
    private static final String EXCEPTION_MSG = "异常类型: {}, 异常消息: {}";
    private static final String VALIDATION_ERROR_MSG = "参数验证失败: {}";
    private static final String UNKNOWN_EXCEPTION_MSG = "未知异常: {}";

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public BlogResult<?> handlerException(Exception exception) {
        HttpServletRequest request = BlogUtil.getRequest();
        String requestURL = (request != null) ? request.getRequestURI().toString() : "无法获取请求URL";

        //使用占位符记录日志
        log.error(REQUEST_URL_MSG, requestURL);
        log.error(EXCEPTION_MSG, exception.getClass().getSimpleName(), exception.getMessage());
        log.error("异常堆栈：", exception);     // 单独记录完整堆栈

        //使用模式匹配处理异常
        return handlerExceptionType(exception);
    }

    /**
     * 根据异常类型处理异常
     * @param exception
     * @return
     */
    private BlogResult<?> handlerExceptionType(Exception exception) {
        if (exception instanceof BlogRuntimeException) {
            return handleBlogRuntimeException((BlogRuntimeException) exception);
        } else if (exception instanceof BlogLoginException) {
            return handleBlogLoginException((BlogLoginException) exception);
        } else if (exception instanceof MethodArgumentNotValidException) {
            return handleValidationException((MethodArgumentNotValidException) exception);
        } else if (exception instanceof MissingServletRequestParameterException) {
            return handleMissingParameterException();
        } else {
            return handleUnknownException(exception);
        }
    }

    /**
     * 处理业务运行时异常
     */
    private BlogResult<?> handleBlogRuntimeException(BlogRuntimeException exception) {
        return BlogResult.fail(exception.getMessage());
    }

    /**
     * 处理登录相关异常
     */
    private BlogResult<?> handleBlogLoginException(BlogLoginException exception) {
        return BlogResult.fail(300, exception.getMessage());
    }

    /**
     * 处理参数验证异常
     */
    private BlogResult<?> handleValidationException(MethodArgumentNotValidException exception) {
        BindingResult bindingResult = exception.getBindingResult();
        Map<String, String> errors = new LinkedHashMap<>();

        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            String fieldName = fieldError.getField();
            String errorMsg = fieldError.getDefaultMessage();
            errors.put(fieldName, errorMsg != null ? errorMsg : "参数错误");
        }

        String errorJson = JSON.toJSONString(errors);
        log.warn(VALIDATION_ERROR_MSG, errorJson);
        return BlogResult.fail(errorJson);
    }

    /**
     * 处理缺少参数异常
     */
    private BlogResult<?> handleMissingParameterException() {
        return BlogResult.fail(CodeMsg.PARAMETER_ERROR);
    }

    /**
     * 处理未知异常
     */
    private BlogResult<?> handleUnknownException(Exception exception) {
        log.error(UNKNOWN_EXCEPTION_MSG, exception.getClass().getName(), exception);
        return BlogResult.fail(CodeMsg.FAIL);
    }

}
